/*
 * Copyright (c) 2017-present, CV4J Contributors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.cv4j.core.filters;

import com.cv4j.core.datamodel.ColorProcessor;
import com.cv4j.core.datamodel.ImageProcessor;
import com.cv4j.core.datamodel.IntIntegralImage;

import java.util.Optional;

/**
 * 马赛克过滤器
 *
 * @author dev
 * @date 2021/07/22
 */
public class MosaicFilter extends BaseFilter {
    // 窗口半径大小
    private int radius = 1;

    /**
     * 马赛克过滤器
     */
    public MosaicFilter() {
        radius = 1;
    }

    /**
     * 得到半径
     *
     * @return int
     */
    public int getRadius() {
        return radius;
    }

    /**
     * 设置半径
     *
     * @param radius radius
     */
    public void setRadius(int radius) {
        this.radius = radius;
    }

    /**
     * 做的过滤器
     *
     * @param src src
     * @return {@link Optional<ImageProcessor>}
     */
    @Override
    public Optional<ImageProcessor> doFilter(ImageProcessor src) {
        int size = (radius * 2 + 1) * (radius * 2 + 1);
        int tr = 0;
        int tg = 0;
        int tb = 0;
        byte[][] output = new byte[3][RED.length];

        IntIntegralImage rii = new IntIntegralImage();
        rii.setImage(RED);
        rii.calculate(width, height);
        IntIntegralImage gii = new IntIntegralImage();
        gii.setImage(GREED);
        gii.calculate(width, height);
        IntIntegralImage bii = new IntIntegralImage();
        bii.setImage(BLUE);
        bii.calculate(width, height);

        dt(size, output, rii, gii, bii);
        ((ColorProcessor) src).putRGB(output[0], output[1], output[2]);
        output = null;
        return Optional.ofNullable(src);
    }

    private void dt(int size, byte[][] output, IntIntegralImage rii, IntIntegralImage gii, IntIntegralImage bii) {
        int tr;
        int tb;
        int tg;
        int x2 = 0;
        int y2 = 0;
        int x1 = 0;
        int y1 = 0;
        int index = 0;
        for (int row = 0; row < height; row++) {
            int dy = (row / size);
            y1 = dy * size;
            y2 = (y1 + size) > height ? (height - 1) : (y1 + size);
            index = row * width;
            for (int col = 0; col < width; col++) {
                int dx = (col / size);
                x1 = dx * size;
                x2 = (x1 + size) > width ? (width - 1) : (x1 + size);
                int sr = rii.getBlockSum(x1, y1, x2, y2);
                int sg = gii.getBlockSum(x1, y1, x2, y2);
                int sb = bii.getBlockSum(x1, y1, x2, y2);
                int num = (x2 - x1) * (y2 - y1);
                if (num == 0) {
                    tr = 0;
                    tg = 0;
                    tb = 0;
                } else {
                    tr = sr / num;
                    tg = sg / num;
                    tb = sb / num;
                }

                output[0][index + col] = (byte) tr;
                output[1][index + col] = (byte) tg;
                output[2][index + col] = (byte) tb;
            }
        }
    }
}
